 /*******************************************************************************
  * Copyright (c) 2003, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.core.runtime.jobs;

 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;

 /**
  * The job manager provides facilities for scheduling, querying, and maintaining jobs
  * and locks. In particular, the job manager provides the following services:
  * <ul>
  * <li>Maintains a queue of jobs that are waiting to be run. Items can be added to
  * the queue using the <code>schedule</code> method.</li>
  * <li>Allows manipulation of groups of jobs called job families. Job families can
  * be canceled, put to sleep, or woken up atomically. There is also a mechanism
  * for querying the set of known jobs in a given family.</li>
  * <li>Allows listeners to find out about progress on running jobs, and to find out
  * when jobs have changed states.</li>
  * <li>Provides a factory for creating lock objects. Lock objects are smart monitors
  * that have strategies for avoiding deadlock.</li>
  * <li>Provide feedback to a client that is waiting for a given job or family of jobs
  * to complete.</li>
  * </ul>
  * <p>
  * This interface is not intended to be implemented by clients.
  * </p>
  *
  * @see Job
  * @see ILock
  * @since 3.0
  */
 public interface IJobManager {
     /**
      * A system property key indicating whether the job manager should create
      * job threads as daemon threads. Set to <code>true</code> to force all worker
      * threads to be created as daemon threads. Set to <code>false</code> to force
      * all worker threads to be created as non-daemon threads.
      * @since 3.3
      */
     public static final String PROP_USE_DAEMON_THREADS = "eclipse.jobs.daemon"; //$NON-NLS-1$

     /**
      * Registers a job listener with the job manager.
      * Has no effect if an identical listener is already registered.
      *
      * @param listener the listener to be added
      * @see #removeJobChangeListener(IJobChangeListener)
      * @see IJobChangeListener
      */
     public void addJobChangeListener(IJobChangeListener listener);

     /**
      * Begins applying this rule in the calling thread. If the rule conflicts with another
      * rule currently running in another thread, this method blocks until there are
      * no conflicting rules. Calls to <tt>beginRule</tt> must eventually be followed
      * by a matching call to <tt>endRule</tt> in the same thread and with the identical
      * rule instance.
      * <p>
      * Rules can be nested only if the rule for the inner <tt>beginRule</tt>
      * is contained within the rule for the outer <tt>beginRule</tt>. Rule containment
      * is tested with the API method <tt>ISchedulingRule.contains</tt>. Also, begin/end
      * pairs must be strictly nested. Only the rule that has most recently begun
      * can be ended at any given time.
      * <p>
      * A rule of <code>null</code> can be used, but will be ignored for scheduling
      * purposes. The outermost non-null rule in the thread will be used for scheduling. A
      * <code>null</code> rule that is begun must still be ended.
      * <p>
      * If this method is called from within a job that has a scheduling rule, the
      * given rule must also be contained within the rule for the running job.
      * <p>
      * Note that <tt>endRule</tt> must be called even if <tt>beginRule</tt> fails.
      * The recommended usage is:
      * <pre>
      * final ISchedulingRule rule = ...;
      * try {
      * manager.beginRule(rule, monitor);
      * } finally {
      * manager.endRule(rule);
      * }
      * </pre>
      *
      * @param rule the rule to begin applying in this thread, or <code>null</code>
      * @param monitor a progress monitor, or <code>null</code> if progress
      * reporting and cancellation are not desired
      * @throws IllegalArgumentException if the rule is not strictly nested within
      * all other rules currently active for this thread
      * @throws OperationCanceledException if the supplied monitor reports cancelation
      * before the rule becomes available
      * @see ISchedulingRule#contains(ISchedulingRule)
      */
     public void beginRule(ISchedulingRule rule, IProgressMonitor monitor);

     /**
      * Cancels all jobs in the given job family. Jobs in the family that are currently waiting
      * will be removed from the queue. Sleeping jobs will be discarded without having
      * a chance to wake up. Currently executing jobs will be asked to cancel but there
      * is no guarantee that they will do so.
      *
      * @param family the job family to cancel, or <code>null</code> to cancel all jobs
      * @see Job#belongsTo(Object)
      */
     public void cancel(Object family);

     /**
      * Returns a progress monitor that can be used to provide
      * aggregated progress feedback on a set of running jobs. A user
      * interface will typically group all jobs in a progress group together,
      * providing progress feedback for individual jobs as well as aggregated
      * progress for the entire group. Jobs in the group may be run sequentially,
      * in parallel, or some combination of the two.
      * <p>
      * Recommended usage (this snippet runs two jobs in sequence in a
      * single progress group):
      * <pre>
      * Job parseJob, compileJob;
      * IProgressMonitor pm = Platform.getJobManager().createProgressGroup();
      * try {
      * pm.beginTask("Building", 10);
      * parseJob.setProgressGroup(pm, 5);
      * parseJob.schedule();
      * compileJob.setProgressGroup(pm, 5);
      * compileJob.schedule();
      * parseJob.join();
      * compileJob.join();
      * } finally {
      * pm.done();
      * }
      * </pre>
      *
      * @see Job#setProgressGroup(IProgressMonitor, int)
      * @see IProgressMonitor
      * @return a progress monitor
      */
     public IProgressMonitor createProgressGroup();

     /**
      * Returns the job that is currently running in this thread, or <code>null</code> if there
      * is no currently running job.
      *
      * @return the job or <code>null</code>
      */
     public Job currentJob();

     /**
      * Ends the application of a rule to the calling thread. Calls to <tt>endRule</tt>
      * must be preceded by a matching call to <tt>beginRule</tt> in the same thread
      * with an identical rule instance.
      * <p>
      * Rules can be nested only if the rule for the inner <tt>beginRule</tt>
      * is contained within the rule for the outer <tt>beginRule</tt>. Also, begin/end
      * pairs must be strictly nested. Only the rule that has most recently begun
      * can be ended at any given time.
      *
      * @param rule the rule to end applying in this thread
      * @throws IllegalArgumentException if this method is called on a rule for which
      * there is no matching begin, or that does not match the most recent begin.
      * @see ISchedulingRule#contains(ISchedulingRule)
      */
     public void endRule(ISchedulingRule rule);

     /**
      * Returns all waiting, executing and sleeping jobs belonging
      * to the given family. If no jobs are found, an empty array is returned.
      *
      * @param family the job family to find, or <code>null</code> to find all jobs
      * @return the job array
      * @see Job#belongsTo(Object)
      */
     public Job[] find(Object family);

     /**
      * Returns whether the job manager is currently idle. The job manager is
      * idle if no jobs are currently running or waiting to run.
      *
      * @return <code>true</code> if the job manager is idle, and
      * <code>false</code> otherwise
      * @since 3.1
      */
     public boolean isIdle();

     /**
      * Waits until all jobs of the given family are finished. This method will block the
      * calling thread until all such jobs have finished executing, or until this thread is
      * interrupted. If there are no jobs in
      * the family that are currently waiting, running, or sleeping, this method returns
      * immediately. Feedback on how the join is progressing is provided to a progress
      * monitor.
      * <p>
      * If this method is called while the job manager is suspended, only jobs
      * that are currently running will be joined; Once there are no jobs
      * in the family in the {@link Job#RUNNING} state, this method returns.
      * </p>
      * <p>
      * Note that there is a deadlock risk when using join. If the calling thread owns
      * a lock or object monitor that the joined thread is waiting for, deadlock
      * will occur. This method can also result in starvation of the current thread if
      * another thread continues to add jobs of the given family, or if a
      * job in the given family reschedules itself in an infinite loop.
      * </p>
      *
      * @param family the job family to join, or <code>null</code> to join all jobs.
      * @param monitor Progress monitor for reporting progress on how the
      * wait is progressing, or <code>null</code> if no progress monitoring is required.
      * @exception InterruptedException if this thread is interrupted while waiting
      * @exception OperationCanceledException if the progress monitor is canceled while waiting
      * @see Job#belongsTo(Object)
      * @see #suspend()
      */
     public void join(Object family, IProgressMonitor monitor) throws InterruptedException , OperationCanceledException;

     /**
      * Creates a new lock object. All lock objects supplied by the job manager
      * know about each other and will always avoid circular deadlock amongst
      * themselves.
      *
      * @return the new lock object
      */
     public ILock newLock();

     /**
      * Removes a job listener from the job manager.
      * Has no effect if an identical listener is not already registered.
      *
      * @param listener the listener to be removed
      * @see #addJobChangeListener(IJobChangeListener)
      * @see IJobChangeListener
      */
     public void removeJobChangeListener(IJobChangeListener listener);

     /**
      * Resumes execution of jobs after a previous <code>suspend</code>. All
      * jobs that were sleeping or waiting prior to the suspension, or that were
      * scheduled while the job manager was suspended, will now be eligible
      * for execution.
      * <p>
      * Calling this method on a rule that is not suspended has no effect. If another
      * thread also owns the rule at the time this method is called, then the rule will
      * not be resumed until all threads have released the rule.
      *
      * @deprecated This method is not safe and should not be used.
      * Suspending a scheduling rule violates the thread safety
      * of clients that use scheduling rules as a mutual exclusion mechanism,
      * and can result in concurrency problems in all clients that use the suspended rule.
      * @see #suspend(ISchedulingRule, IProgressMonitor)
      */
     public void resume(ISchedulingRule rule);

     /**
      * Resumes execution of jobs after a previous <code>suspend</code>. All
      * jobs that were sleeping or waiting prior to the suspension, or that were
      * scheduled while the job manager was suspended, will now be eligible
      * for execution.
      * <p>
      * Calling <code>resume</code> when the job manager is not suspended
      * has no effect.
      *
      * @see #suspend()
      */
     public void resume();

     /**
      * Provides a hook that is notified whenever a thread is about to wait on a lock,
      * or when a thread is about to release a lock. This hook must only be set once.
      * <p>
      * This method is for internal use by the platform-related plug-ins.
      * Clients should not call this method.
      * </p>
      * @see LockListener
      */
     public void setLockListener(LockListener listener);

     /**
      * Registers a progress provider with the job manager. If there was a
      * provider already registered, it is replaced.
      * <p>
      * This method is intended for use by the currently executing Eclipse application.
      * Plug-ins outside the currently running application should not call this method.
      * </p>
      *
      * @param provider the new provider, or <code>null</code> if no progress
      * is needed
      */
     public void setProgressProvider(ProgressProvider provider);

     /**
      * Suspends execution of all jobs. Jobs that are already running
      * when this method is invoked will complete as usual, but all sleeping and
      * waiting jobs will not be executed until the job manager is resumed.
      * <p>
      * The job manager will remain suspended until a subsequent call to
      * <code>resume</code>. Further calls to <code>suspend</code>
      * when the job manager is already suspended are ignored.
      * <p>
      * All attempts to join sleeping and waiting jobs while the job manager is
      * suspended will return immediately.
      * <p>
      * Note that this very powerful function should be used with extreme caution.
      * Suspending the job manager will prevent all jobs in the system from executing,
      * which may have adverse affects on components that are relying on
      * execution of jobs. The job manager should never be suspended without intent
      * to resume execution soon afterwards.
      *
      * @see #resume()
      * @see #join(Object, IProgressMonitor)
      */
     public void suspend();

     /**
      * Defers execution of all jobs with scheduling rules that conflict with the
      * given rule. The caller will be blocked until all currently executing jobs with
      * conflicting rules are completed. Conflicting jobs that are sleeping or waiting at
      * the time this method is called will not be executed until the rule is resumed.
      * <p>
      * While a rule is suspended, all calls to <code>beginRule</code> and
      * <code>endRule</code> on a suspended rule will not block the caller.
      * The rule remains suspended until a subsequent call to
      * <code>resume(ISchedulingRule)</code> with the identical rule instance.
      * Further calls to <code>suspend</code> with an identical rule prior to calling
      * <code>resume</code> are ignored.
      * </p>
      * <p>
      * This method is long-running; progress and cancelation are provided by
      * the given progress monitor. In the case of cancelation, the rule will
      * not be suspended.
      * </p>
      * Note: this very powerful function should be used with extreme caution.
      * Suspending rules will prevent jobs in the system from executing, which may
      * have adverse effects on components that are relying on execution of jobs.
      * The job manager should never be suspended without intent to resume
      * execution soon afterwards. Deadlock will result if the thread responsible
      * for resuming the rule attempts to join a suspended job.
      *
      * @deprecated This method is not safe and should not be used.
      * Suspending a scheduling rule violates the thread safety
      * of clients that use scheduling rules as a mutual exclusion mechanism,
      * and can result in concurrency problems in all clients that use the suspended rule.
      * @param rule The scheduling rule to suspend. Must not be <code>null</code>.
      * @param monitor a progress monitor, or <code>null</code> if progress
      * reporting is not desired
      * @exception OperationCanceledException if the operation is canceled.
      * Cancelation can occur even if no progress monitor is provided.
      * @see #resume(ISchedulingRule)
      */
     public void suspend(ISchedulingRule rule, IProgressMonitor monitor);

     /**
      * Requests that all jobs in the given job family be suspended. Jobs currently
      * waiting to be run will be removed from the queue and moved into the
      * <code>SLEEPING</code> state. Jobs that have been put to sleep
      * will remain in that state until either resumed or canceled. This method has
      * no effect on jobs that are not currently waiting to be run.
      * <p>
      * Sleeping jobs can be resumed using <code>wakeUp</code>.
      *
      * @param family the job family to sleep, or <code>null</code> to sleep all jobs.
      * @see Job#belongsTo(Object)
      */
     public void sleep(Object family);

     /**
      * Transfers ownership of a scheduling rule to another thread. The identical
      * scheduling rule must currently be owned by the calling thread as a result of
      * a previous call to <code>beginRule</code>. The destination thread must
      * not already own a scheduling rule.
      * <p>
      * Calling this method is equivalent to atomically calling <code>endRule</code>
      * in the calling thread followed by an immediate <code>beginRule</code> in
      * the destination thread. The destination thread is responsible for subsequently
      * calling <code>endRule</code> when it is finished using the rule.
      * <p>
      * This method has no effect when the destination thread is the same as the
      * calling thread.
      *
      * @param rule The scheduling rule to transfer
      * @param destinationThread The new owner for the transferred rule.
      * @since 3.1
      */
     public void transferRule(ISchedulingRule rule, Thread destinationThread);

     /**
      * Resumes scheduling of all sleeping jobs in the given family. This method
      * has no effect on jobs in the family that are not currently sleeping.
      *
      * @param family the job family to wake up, or <code>null</code> to wake up all jobs
      * @see Job#belongsTo(Object)
      */
     public void wakeUp(Object family);
 }

